package org.light.generator;

import java.util.ArrayList;
import java.util.List;

import org.light.core.Writeable;
import org.light.domain.Domain;
import org.light.domain.Statement;
import org.light.domain.StatementList;
import org.light.utils.RandomUtil;
import org.light.utils.StringUtil;
import org.light.utils.WriteableUtil;

public class MainRsGenerator extends Generator{
	protected boolean containsAuth = false;
	public boolean isContainsAuth() {
		return containsAuth;
	}

	public void setContainsAuth(boolean containsAuth) {
		this.containsAuth = containsAuth;
	}

	protected List<Domain> domains = new ArrayList<>();
	public List<Domain> getDomains() {
		return domains;
	}

	public void setDomains(List<Domain> domains) {
		this.domains = domains;
	}

	public MainRsGenerator(){
		super();
		super.fileName = "main.rs";
		super.standardName = "MainRs";
	}

	@Override
	public StatementList generateStatementList() {
		Domain sampleDomain = this.domains.get(0);
		List<Writeable> sList = new ArrayList<Writeable>();
		sList.add(new Statement(100L,0,"#[macro_use]"));
		sList.add(new Statement(200L,0,"extern crate lazy_static;"));
		sList.add(new Statement(400L,0,"extern crate simple_excel_writer as excel;"));
		sList.add(new Statement(1000L,0,"mod "+sampleDomain.getControllerSuffix()+";"));
		sList.add(new Statement(2000L,0,"mod "+sampleDomain.getServiceimplSuffix()+";"));
		sList.add(new Statement(2200L,0,"mod utils;"));
		if (this.containsAuth) {
			sList.add(new Statement(2300L,0,"mod middleware;"));
		}
		sList.add(new Statement(3000L,0,""));

		sList.add(new Statement(4000L,0,"use axum::{"));
		sList.add(new Statement(4100L,1,"extract::{Form, Path, Query},"));
		sList.add(new Statement(4200L,1,"http:: {HeaderMap, HeaderValue,StatusCode},"));
		sList.add(new Statement(4300L,1,"routing::{get_service,get,post,MethodRouter},"));
		sList.add(new Statement(4400L,1,"response::IntoResponse,"));
		sList.add(new Statement(4500L,1,"Extension,"));
		sList.add(new Statement(4600L,1,"Router"));
		sList.add(new Statement(4700L,0,"};"));
		sList.add(new Statement(4800L,0,""));
		
		sList.add(new Statement(5000L,0,"use axum_sessions::{"));
		sList.add(new Statement(5100L,1,"async_session::MemoryStore, extractors::WritableSession, PersistencePolicy, SessionLayer,"));
		sList.add(new Statement(5200L,0,"};"));
		
		sList.add(new Statement(10000L,0,""));
		sList.add(new Statement(11000L,0,"use std::net::SocketAddr;"));
		sList.add(new Statement(12000L,0,"use tower_http::{services::ServeDir, trace::TraceLayer};"));
		sList.add(new Statement(14000L,0,"use serde_json;"));
		sList.add(new Statement(15000L,0,"use "+sampleDomain.getProjectName()+"::AppState;"));
		sList.add(new Statement(16000L,0,"use "+sampleDomain.getProjectName()+"::config::Config;"));
		sList.add(new Statement(18000L,0,"use std::sync::{Arc, Mutex};"));
		sList.add(new Statement(19000L,0,"use std::collections::HashMap;"));
		sList.add(new Statement(21000L,0,"use serde_json::{Value,Map};"));
		sList.add(new Statement(23000L,0,"use tower_http::cors::{Any, CorsLayer};"));
		sList.add(new Statement(24000L,0,"use http::{Method};"));
		long serial = 25000L;
		for (Domain d:this.domains) {
			sList.add(new Statement(serial,0,"use crate::"+d.getControllerSuffix()+"::"+d.getSnakeDomainName()+"_"+StringUtil.getSnakeName(d.getControllerNamingSuffix())+"::"+d.getSnakeDomainName()+"_"+StringUtil.getSnakeName(d.getControllerNamingSuffix())+";"));
			serial += 1000L;
		}
		if (containsAuth) {
			Domain d = this.domains.get(0);
			sList.add(new Statement(serial,0,"use axum::middleware::from_fn;"));
			sList.add(new Statement(serial+1000L,0,"use crate::middleware::login_middleware::check_auth;"));
			sList.add(new Statement(serial,0,"use crate::"+d.getControllerSuffix()+"::login_"+StringUtil.getSnakeName(d.getControllerNamingSuffix())+"::login_"+StringUtil.getSnakeName(d.getControllerNamingSuffix())+";"));
		}
		sList.add(new Statement(serial+2000L,0,""));
		sList.add(new Statement(serial+3000L,0,"#[tokio::main]"));
		sList.add(new Statement(serial+4000L,0,"async fn main() {"));
		
		sList.add(new Statement(serial+5000L,1,"let store = MemoryStore::new();"));
		sList.add(new Statement(serial+6000L,1,"let secret = b\""+RandomUtil.getRandomBase62String(64)+"\"; // MUST be at least 64 bytes!"));
		sList.add(new Statement(serial+7000L,1,"let session_layer = SessionLayer::new(store, secret);"));
		
		sList.add(new Statement(serial+37100L,1,"let cors = CorsLayer::new()"));
		sList.add(new Statement(serial+37200L,1,"// allow `GET` and `POST` when accessing the resource"));
		sList.add(new Statement(serial+37300L,1,".allow_methods([Method::GET, Method::POST])"));
		sList.add(new Statement(serial+37400L,1,"// allow requests from any origin"));
		sList.add(new Statement(serial+37500L,1,".allow_origin(Any)"));
		sList.add(new Statement(serial+37600L,1,".allow_headers(Any);"));
		sList.add(new Statement(serial+37700L,0,""));
		sList.add(new Statement(serial+38000L,1,"// Set the RUST_LOG, if it hasn't been explicitly defined"));
		sList.add(new Statement(serial+39000L,1,"if std::env::var_os(\"RUST_LOG\").is_none() {"));
		sList.add(new Statement(serial+40000L,2,"std::env::set_var("));
		sList.add(new Statement(serial+41000L,3,"\"RUST_LOG\","));
		sList.add(new Statement(serial+42000L,3,"\"example_static_file_server=debug,tower_http=debug\","));
		sList.add(new Statement(serial+43000L,2,")"));
		sList.add(new Statement(serial+44000L,1,"}"));
		
		sList.add(new Statement(serial+45000L,1,"let routes = Router::new()"));
		serial += 46000L;
		for (Domain d:this.domains) {
			sList.add(new Statement(serial,2,".nest(\"/"+d.getLowerFirstDomainName()+d.getControllerNamingSuffix()+"\", "+d.getSnakeDomainName()+"_"+StringUtil.getSnakeName(d.getControllerNamingSuffix())+"())"));
			serial += 1000L;
		}
		if (containsAuth) {
			sList.add(new Statement(serial,3,".layer(from_fn(check_auth));"));
		}

		sList.add(new Statement(serial+57000L,1,"let app = Router::new()"));
		sList.add(new Statement(serial+58000L,2,".nest_service("));
		sList.add(new Statement(serial+59000L,3,"\"/pages\","));
		sList.add(new Statement(serial+60000L,3,"get_service(ServeDir::new(\"./template/pages/\")).handle_error(|error: std::io::Error| async move {"));
		sList.add(new Statement(serial+61000L,4,"("));
		sList.add(new Statement(serial+62000L,5,"StatusCode::INTERNAL_SERVER_ERROR,"));
		sList.add(new Statement(serial+63000L,5,"format!(\"Unhandled internal error: {}\", error),"));
		sList.add(new Statement(serial+64000L,4,")"));
		sList.add(new Statement(serial+65000L,3,"}),"));
		sList.add(new Statement(serial+66000L,2,")"));
		sList.add(new Statement(serial+67000L,3,".nest_service("));
		sList.add(new Statement(serial+68000L,4,"\"/css\","));
		sList.add(new Statement(serial+69000L,3,"get_service(ServeDir::new(\"./template/css/\")).handle_error(|error: std::io::Error| async move {"));
		sList.add(new Statement(serial+70000L,4,"("));
		sList.add(new Statement(serial+71000L,5,"StatusCode::INTERNAL_SERVER_ERROR,"));
		sList.add(new Statement(serial+72000L,5,"format!(\"Unhandled internal error: {}\", error),"));
		sList.add(new Statement(serial+73000L,4,")"));
		sList.add(new Statement(serial+74000L,3,"}),"));
		sList.add(new Statement(serial+75000L,2,")"));
		sList.add(new Statement(serial+76000L,2,".nest_service("));
		sList.add(new Statement(serial+77000L,3,"\"/js\","));
		sList.add(new Statement(serial+78000L,3,"get_service(ServeDir::new(\"./template/js/\")).handle_error(|error: std::io::Error| async move {"));
		sList.add(new Statement(serial+79000L,4,"("));
		sList.add(new Statement(serial+80000L,5,"StatusCode::INTERNAL_SERVER_ERROR,"));
		sList.add(new Statement(serial+81000L,5,"format!(\"Unhandled internal error: {}\", error),"));
		sList.add(new Statement(serial+82000L,4,")"));
		sList.add(new Statement(serial+83000L,3,"}),"));
		sList.add(new Statement(serial+84000L,2,")"));
		sList.add(new Statement(serial+85000L,2,".nest_service("));
		sList.add(new Statement(serial+86000L,3,"\"/easyui\","));
		sList.add(new Statement(serial+87000L,3,"get_service(ServeDir::new(\"./template/easyui/\")).handle_error(|error: std::io::Error| async move {"));
		sList.add(new Statement(serial+88000L,4,"("));
		sList.add(new Statement(serial+89000L,5,"StatusCode::INTERNAL_SERVER_ERROR,"));
		sList.add(new Statement(serial+90000L,5,"format!(\"Unhandled internal error: {}\", error),"));
		sList.add(new Statement(serial+91000L,4,")"));
		sList.add(new Statement(serial+92000L,3,"}),"));
		sList.add(new Statement(serial+93000L,2,")"));
		sList.add(new Statement(serial+94000L,4,".nest_service("));
		sList.add(new Statement(serial+95000L,3,"\"/echarts\","));
		sList.add(new Statement(serial+96000L,3,"get_service(ServeDir::new(\"./template/echarts/\")).handle_error(|error: std::io::Error| async move {"));
		sList.add(new Statement(serial+97000L,4,"("));
		sList.add(new Statement(serial+98000L,5,"StatusCode::INTERNAL_SERVER_ERROR,"));
		sList.add(new Statement(serial+99000L,5,"format!(\"Unhandled internal error: {}\", error),"));
		sList.add(new Statement(serial+100000L,4,")"));
		sList.add(new Statement(serial+101000L,3,"}),"));
		sList.add(new Statement(serial+102000L,2,")"));
		sList.add(new Statement(serial+103000L,2,".nest_service("));
		sList.add(new Statement(serial+104000L,3,"\"/images\","));
		sList.add(new Statement(serial+105000L,3,"get_service(ServeDir::new(\"./template/images/\")).handle_error(|error: std::io::Error| async move {"));
		sList.add(new Statement(serial+106000L,4,"("));
		sList.add(new Statement(serial+107000L,5,"StatusCode::INTERNAL_SERVER_ERROR,"));
		sList.add(new Statement(serial+108000L,5,"format!(\"Unhandled internal error: {}\", error),"));
		sList.add(new Statement(serial+109000L,4,")"));
		sList.add(new Statement(serial+110000L,3,"}),"));
		sList.add(new Statement(serial+111000L,2,")"));
		sList.add(new Statement(serial+112000L,2,".nest_service("));
		sList.add(new Statement(serial+113000L,3,"\"/error\","));
		sList.add(new Statement(serial+114000L,3,"get_service(ServeDir::new(\"./template/error/\")).handle_error(|error: std::io::Error| async move {"));
		sList.add(new Statement(serial+115000L,4,"("));
		sList.add(new Statement(serial+116000L,5,"StatusCode::INTERNAL_SERVER_ERROR,"));
		sList.add(new Statement(serial+117000L,5,"format!(\"Unhandled internal error: {}\", error),"));
		sList.add(new Statement(serial+118000L,4,")"));
		sList.add(new Statement(serial+119000L,3,"}),"));
		sList.add(new Statement(serial+120000L,2,")"));
		sList.add(new Statement(serial+121000L,2,".nest_service("));
		sList.add(new Statement(serial+122000L,3,"\"/uploadjs\","));
		sList.add(new Statement(serial+123000L,3,"get_service(ServeDir::new(\"./template/uploadjs/\")).handle_error(|error: std::io::Error| async move {"));
		sList.add(new Statement(serial+124000L,4,"("));
		sList.add(new Statement(serial+125000L,5,"StatusCode::INTERNAL_SERVER_ERROR,"));
		sList.add(new Statement(serial+126000L,5,"format!(\"Unhandled internal error: {}\", error),"));
		sList.add(new Statement(serial+127000L,4,")"));
		sList.add(new Statement(serial+128000L,3,"}),"));
		sList.add(new Statement(serial+129000L,2,")"));
		sList.add(new Statement(serial+130000L,2,".nest_service("));
		sList.add(new Statement(serial+131000L,3,"\"/login\","));
		sList.add(new Statement(serial+132000L,3,"get_service(ServeDir::new(\"./template/login/\")).handle_error(|error: std::io::Error| async move {"));
		sList.add(new Statement(serial+133000L,4,"("));
		sList.add(new Statement(serial+134000L,5,"StatusCode::INTERNAL_SERVER_ERROR,"));
		sList.add(new Statement(serial+135000L,5,"format!(\"Unhandled internal error: {}\", error),"));
		sList.add(new Statement(serial+136000L,4,")"));
		sList.add(new Statement(serial+137000L,3,"}),"));
		sList.add(new Statement(serial+138000L,2,")"));
		sList.add(new Statement(serial+139000L,2,".route("));
		sList.add(new Statement(serial+140000L,3,"\"/\","));
		sList.add(new Statement(serial+141000L,3,"get_service(ServeDir::new(\"./template/index.html\")).handle_error(|error: std::io::Error| async move {"));
		sList.add(new Statement(serial+142000L,4,"("));
		sList.add(new Statement(serial+143000L,5,"StatusCode::INTERNAL_SERVER_ERROR,"));
		sList.add(new Statement(serial+144000L,5,"format!(\"Unhandled internal error: {}\", error),"));
		sList.add(new Statement(serial+145000L,4,")"));
		sList.add(new Statement(serial+146000L,3,"}),"));
		sList.add(new Statement(serial+147000L,2,")"));

		sList.add(new Statement(serial+148000L,2,".nest(\"/"+sampleDomain.getControllerPackagePrefix()+"\", routes)"));
		if (containsAuth) {
			sList.add(new Statement(serial+149000L,2,".nest(\"/login"+sampleDomain.getControllerNamingSuffix()+"\",login_"+StringUtil.getSnakeName(sampleDomain.getControllerNamingSuffix())+"())"));
		}
		sList.add(new Statement(serial+161000L,2,".layer(cors)"));
		sList.add(new Statement(serial+162000L,2,".layer(session_layer);"));
		sList.add(new Statement(serial+163000L,0,""));
		sList.add(new Statement(serial+164000L,1,"let addr = SocketAddr::from(([127, 0, 0, 1], 8082));"));
		sList.add(new Statement(serial+165000L,1,"tracing::debug!(\"listening on {}\", addr);"));
		sList.add(new Statement(serial+166000L,1,"axum::Server::bind(&addr)"));
		sList.add(new Statement(serial+167000L,2,".serve(app.into_make_service())"));
		sList.add(new Statement(serial+168000L,2,".await"));
		sList.add(new Statement(serial+169000L,2,".unwrap();"));
		sList.add(new Statement(serial+170000L,0,"}"));
		sList.add(new Statement(serial+171000L,0,""));

		return WriteableUtil.merge(sList);
	}

}
